<?
class zimbraAdmin {
	private $ServerAddress;
	private $SessionID;
	private $AuthToken;
	private $AdminUsername;
	private $AdminPassword;
	private $DefaultCOS;
	private $CurlHandle;
	private $error;
	private $fault;
	private $CurrentResponse;
	private $CurrentRequest;
	
	// Get an XML Tree from the XML code $xmlloc
	function GetXMLTree($xml) { 

		$data = $xml;

		$parser = xml_parser_create('ISO-8859-1');
		xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
		xml_parse_into_struct($parser, $data, $vals, $index); 
		xml_parser_free($parser); 

		$tree = array(); 
		$i = 0; 
	  
		if (isset($vals[$i]['attributes'])) {
			$tree[$vals[$i]['tag']][]['ATTRIBUTES'] = $vals[$i]['attributes']; 
			$index = count($tree[$vals[$i]['tag']])-1;
			$tree[$vals[$i]['tag']][$index] =  array_merge($tree[$vals[$i]['tag']][$index], $this->__getchildren($vals, $i));
		} else {
			$tree[$vals[$i]['tag']][] = $this->__getchildren($vals, $i); 
		}
	  
		return $tree;
	} 
	
	// Get children of the current node
	function __getchildren($vals, &$i)  { 
		$children = array();     // Contains node data

		/* Node has CDATA before it's children */
		if (isset($vals[$i]['value'])) 
		$children['VALUE'] = $vals[$i]['value']; 

		/* Loop through children */
		while (++$i < count($vals)) { 
			switch ($vals[$i]['type']) { 
				/* Node has CDATA after one of it's children 
				(Add to cdata found before if this is the case) */
				case 'cdata': 
					if (isset($children['VALUE']))
					  $children['VALUE'] .= $vals[$i]['value']; 
					else
					  $children['VALUE'] = $vals[$i]['value']; 
					break;
				/* At end of current branch */ 
				case 'complete': 
					if (isset($vals[$i]['attributes'])) {
					  $children[$vals[$i]['tag']][]['ATTRIBUTES'] = $vals[$i]['attributes'];
					  $index = count($children[$vals[$i]['tag']])-1;

					  if (isset($vals[$i]['value'])) 
						$children[$vals[$i]['tag']][$index]['VALUE'] = $vals[$i]['value']; 
					  else
						$children[$vals[$i]['tag']][$index]['VALUE'] = ''; 
					} else {
					  if (isset($vals[$i]['value'])) 
						$children[$vals[$i]['tag']][]['VALUE'] = $vals[$i]['value']; 
					  else
						$children[$vals[$i]['tag']][]['VALUE'] = ''; 
					}
					break; 
				/* Node has more children */
				case 'open': 
					if (isset($vals[$i]['attributes'])) {
					  $children[$vals[$i]['tag']][]['ATTRIBUTES'] = $vals[$i]['attributes'];
					  $index = count($children[$vals[$i]['tag']])-1;
					  $children[$vals[$i]['tag']][$index] = array_merge($children[$vals[$i]['tag']][$index],$this->__getchildren($vals, $i));
					} else {
					  $children[$vals[$i]['tag']][] = $this->__getchildren($vals, $i);
					}
					break; 
				/* End of node, return collected data */
				case 'close': 
					return $children; 
			} 
		} 
	}
	
	function zimbraAdmin($server = NULL) {
		$this->CurlHandle = curl_init();
		curl_setopt($this->CurlHandle, CURLOPT_POST,           TRUE);
        curl_setopt($this->CurlHandle, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($this->CurlHandle, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($this->CurlHandle, CURLOPT_SSL_VERIFYHOST, FALSE);
		
		if ($server) {
			$this->ServerAddress = $server;
			curl_setopt($this->CurlHandle, CURLOPT_URL, 'https://'.$this->ServerAddress.':7071/service/admin/soap');
		}
		
		$this->error = array();
		$this->fault = array();
	}

	function Connect($AdminUsername, $AdminPassword, $server = NULL) {
		$this->AdminUsername = $AdminUsername;
		$this->AdminPassword = $AdminPassword;
		
		// Set our server URL
		if ($server) {
			$this->ServerAddress = $server;
			curl_setopt($this->CurlHandle, CURLOPT_URL, 'https://'.$this->ServerAddress.':7071/service/admin/soap');
		}
		
		// Build admin authentication request
		$SOAPMessage  = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
												<soap:Header>
														<context xmlns="urn:zimbra"/>
												</soap:Header>
												<soap:Body>
														<AuthRequest xmlns="urn:zimbraAdmin">
																<name>' . $this->AdminUsername . '</name>
																<password>' . $this->AdminPassword . '</password>
														</AuthRequest>
												</soap:Body>
										</soap:Envelope>';
		
        if ($this->__execute($SOAPMessage)) {
			 // Parse for the sessionId
			// <sessionId type="admin" id="123">123</sessionId>
			$sessionId = strstr($this->CurrentResponse, "<sessionId");
			$sessionId = strstr($sessionId, ">");
			$this->SessionID = substr($sessionId, 1, strpos($sessionId, "<") - 1);

			// Parse for the authToken
			// <authToken>123</authToken>
			$authToken = strstr($this->CurrentResponse, "<authToken");
			$authToken = strstr($authToken, ">");
			$this->AuthToken = substr($authToken, 1, strpos($authToken, "<") - 1);
			
			return(true);
		} else {
			return(false);
		}
	}
	
	function GetError() {
		return array_pop($this->error);
	}
	
	function __execute($SOAPMessage) {
		curl_setopt($this->CurlHandle, CURLOPT_POSTFIELDS, $SOAPMessage);
		$this->CurrentRequest = $SOAPMessage;
        if(!($ZimbraSOAPResponse = curl_exec($this->CurlHandle))) {
			$this->error[] = array('CURL.Failure', 'curl_exec - (' . curl_errno($CurlHandle) . ') ' . curl_error($CurlHandle));
			return(false);
        } else {
			$this->CurrentResponse = $ZimbraSOAPResponse;
			$xml = $this->GetXMLTree($this->CurrentResponse);
			if (isset($xml['SOAP:ENVELOPE'][0]['SOAP:BODY'][0]['SOAP:FAULT'])) {
				$err_code = $xml['SOAP:ENVELOPE'][0]['SOAP:BODY'][0]['SOAP:FAULT'][0]['SOAP:DETAIL'][0]['ERROR'][0]['CODE'][0]['VALUE'];
				$err_reason = $xml['SOAP:ENVELOPE'][0]['SOAP:BODY'][0]['SOAP:FAULT'][0]['SOAP:REASON'][0]['SOAP:TEXT'][0]['VALUE'];
				$this->error[] = array($err_code, $err_reason);
				return(false);
			} else {
				return(true);
			}
		}
	}
	
	function __rh() {
		$header = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
								<soap:Header>
										<context xmlns="urn:zimbra">
												<authToken>' . $this->AuthToken . '</authToken>
												<sessionId id="' . $this->SessionID . '">' . $this->SessionID . '</sessionId>
										</context>
								</soap:Header>
								<soap:Body>';
		return $header;
	}
	
	function __rf() {
		$footer = '	</soap:Body>
						</soap:Envelope>';
		return $footer;
	}
	
	function GetDefaultCOS() { 
	
		if ($this->DefaultCOS) {
			return($this->DefaultCOS);
		} else {
			$this->DefaultCOS = $this->GetCOS('default');
			return($this->DefaultCOS);
		}
		
	}
	
	function GetCOS($COSName) {
		// Build request
		$SOAPMessage = $this->__rh().'
										<GetCosRequest xmlns="urn:zimbraAdmin">
												<cos by="name">' . $COSName . '</cos>
										</GetCosRequest>
									'.$this->__rf();
									
		if($this->__execute($SOAPMessage)) {
			$COSID = strstr($this->CurrentResponse, '<cos id=');
			$COSID = strstr($COSID, '"');
			if (strlen($COSID)) {
				$COSID = substr($COSID, 1, strpos($COSID, '"', 1) - 1);
			}
			return($COSID);
		} else {
			return(false);
		}
	}
	
	function CreateAccount($NewUsername, $NewPassword, $COSID = NULL) {
		
		if ($COSID == NULL) {
			$COSID = $this->GetDefaultCOS();
		}
		
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <CreateAccountRequest xmlns="urn:zimbraAdmin">
                                                <name>' . $NewUsername . '</name>
                                                <password>' . $NewPassword . '</password>
                                                <a n="zimbraCOSId">' . $COSID . '</a>
                                        </CreateAccountRequest>
									'.$this->__rf();
									
		return($this->__execute($SOAPMessage));
	}

	function AddAccountAlias($Username, $Alias) {
		$AccountID = $this->GetAccountID($Username);
		
		if ($AccountID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<AddAccountAliasRequest xmlns="urn:zimbraAdmin">
													<id>' . $AccountID . '</id>
													<alias>' . $Alias . '</alias>
											</AddAccountAliasRequest>
										'.$this->__rf();
										
			return($this->__execute($SOAPMessage));
		} else {
			return false;
		}
	}
	
	function RemoveAccountAlias($Username, $Alias) {
		$AccountID = $this->GetAccountID($Username);
		
		if ($AccountID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<RemoveAccountAliasRequest xmlns="urn:zimbraAdmin">
													<id>' . $AccountID . '</id>
													<alias>' . $Alias . '</alias>
											</RemoveAccountAliasRequest>
										'.$this->__rf();
										
			return($this->__execute($SOAPMessage));
		} else {
			return false;
		}
	}
	
	function GetAccountAliases($Username) {
		$aliases = array();
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <GetAccountRequest xmlns="urn:zimbraAdmin">
                                                <account by="name">' . $Username . '</account>
                                        </GetAccountRequest>
									'.$this->__rf();
									
		if($this->__execute($SOAPMessage)) {
			$xml = $this->GetXMLTree($this->CurrentResponse);
			$account_attributes = $xml['SOAP:ENVELOPE'][0]['SOAP:BODY'][0]['GETACCOUNTRESPONSE'][0]['ACCOUNT'][0]['A'];
			foreach($account_attributes as $aa) {
				if ($aa['ATTRIBUTES']['N'] == 'zimbraMailAlias') {
					$aliases[] = $aa['VALUE'];
				}
			}
			return($aliases);
		} else {
			return(false);
		}
	}
	
	function AccountExists($Username) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <GetAccountRequest xmlns="urn:zimbraAdmin">
                                                <account by="name">' . $Username . '</account>
                                        </GetAccountRequest>
									'.$this->__rf();
									
		if($this->__execute($SOAPMessage)) {
			return(true);
		} else {
			$error = $this->GetError();
			if (!$error[0] == 'account.NO_SUCH_ACCOUNT') {
				$this->error[] = $error;
			}
			return(false);
		}
	}

	function RenameAccount($OldUsername, $NewUsername) {
		$AccountID = $this->GetAccountID($OldUsername);
		
		if ($AccountID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<RenameAccountRequest xmlns="urn:zimbraAdmin">
													<id>' . $AccountID . '</id>
													<newName>' . $NewUsername . '</newName>
											</RenameAccountRequest>
										'.$this->__rf();
										
			return($this->__execute($SOAPMessage));
		} else {
			return(false);
		}
	}
	
	function SetAccountAttributes($Username, $Attributes = array()) {
		$AccountID = $this->GetAccountID($Username);
		
		if (!$AccountID) {
			return(false);
		}
		
		// Build request
		$SOAPMessage = $this->__rh().'
										<ModifyAccountRequest xmlns="urn:zimbraAdmin">
												<id>' . $AccountID . '</id>';
												foreach($Attributes as $key => $val) {
													$SOAPMessage .= '<a n="'.$key.'">' . $val . '</a>';
												}
		$SOAPMessage .= '</ModifyAccountRequest>
									'.$this->__rf();
									
		return($this->__execute($SOAPMessage));		
	}
	
	function GetAccountID($Username) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <GetAccountRequest xmlns="urn:zimbraAdmin">
                                                <account by="name">' . $Username . '</account>
                                        </GetAccountRequest>
									'.$this->__rf();
									
		if($this->__execute($SOAPMessage)) {
			$AccountID = strstr($this->CurrentResponse, '<account ');
			$AccountID = strstr($AccountID, 'id="');
			if (strlen($AccountID)) {
				$AccountID = substr($AccountID, 4, strpos($AccountID, '"', 4) - 4);
			}
			return($AccountID);
		} else {
			return(false);
		}
	}
	
	function DeleteAccount($Username) {
		$AccountID = $this->GetAccountID($Username);
		
		if ($AccountID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<DeleteAccountRequest xmlns="urn:zimbraAdmin">
													<id>' . $AccountID . '</id>
											</DeleteAccountRequest>
										'.$this->__rf();
							
			if($this->__execute($SOAPMessage)) {
				return(true);
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}
	
	function SetAccountPassword($Username, $NewPassword) {
		$AccountID = $this->GetAccountID($Username);
		
		if ($AccountID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<SetPasswordRequest xmlns="urn:zimbraAdmin">
													<id>' . $AccountID . '</id>
													<newPassword>' . $NewPassword . '</newPassword>
											</SetPasswordRequest>
										'.$this->__rf();
							
			if($this->__execute($SOAPMessage)) {
				return(true);
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}
	
	function CreateDomain($Domain, $notes = NULL) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <CreateDomainRequest xmlns="urn:zimbraAdmin">
                                                <name>' . $Domain . '</name>';
												if ($notes) {
													$SOAPMessage .= '<a n="zimbraNotes">' . $notes . '</a>';
												}
                                        $SOAPMessage .= '</CreateDomainRequest>
									'.$this->__rf();
						
		return($this->__execute($SOAPMessage));
	}
	
	function AddDomainAlias($Domain, $Alias) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <CreateDomainRequest xmlns="urn:zimbraAdmin">
                                                <name>' . $Alias . '</name>';
												if ($notes) {
													$SOAPMessage .= '<a n="zimbraNotes">' . $notes . '</a>';
												}
				$SOAPMessage .= ' <a n="zimbraDomainType">alias</a>
												<a n="zimbraMailCatchAllAddress">@'.$Alias.'</a>
												<a n="zimbraMailCatchAllForwardingAddress">@'.$Domain.'</a>
										</CreateDomainRequest>
									'.$this->__rf();

		return($this->__execute($SOAPMessage));
	}
	
	function RemoveDomainAlias($Alias) {
		return $this->DeleteDomain($Alias);
	}
	
	function GetDomainID($Domain) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <GetDomainRequest xmlns="urn:zimbraAdmin">
                                                <domain by="name">' . $Domain . '</domain>
                                        </GetDomainRequest>
									'.$this->__rf();
						
		if($this->__execute($SOAPMessage)) {
			$DomainID = strstr($this->CurrentResponse, '<domain id=');
			$DomainID = strstr($DomainID, '"');
			$DomainID = substr($DomainID, 1, strpos($DomainID, '"', 1) - 1);
			return($DomainID);
		} else {
			return(false);
		}
	}
	
	function DomainExists($Domain) {
		// Build request
        $SOAPMessage = $this->__rh().'
                                        <GetDomainRequest xmlns="urn:zimbraAdmin">
                                                <domain by="name">' . $Domain . '</domain>
                                        </GetDomainRequest>
									'.$this->__rf();
						
		if($this->__execute($SOAPMessage)) {
			return(true);
		} else {
			$error = $this->GetError();
			if (!$error[0] == 'account.NO_SUCH_DOMAIN') {
				$this->error[] = $error;
			}
			return(false);
		}
	}
	
	function RenameDomain($NewDomain, $OldDomain) {
		$DomainID = $this->GetDomainID($OldDomain);
		
		if ($DomainID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<ModifyDomainRequest xmlns="urn:zimbraAdmin">
													<id>' . $DomainID . '</id>
													<a n="name">' . $NewDomain . '</a>
											</ModifyDomainRequest>
										'.$this->__rf();
							
			if($this->__execute($SOAPMessage)) {
				return(true);
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}
	
	function DeleteDomain($Domain) {
		$DomainID = $this->GetDomainID($Domain);
		
		if ($DomainID) {
			// Build request
			$SOAPMessage = $this->__rh().'
											<DeleteDomainRequest xmlns="urn:zimbraAdmin">
													<id>' . $DomainID . '</id>
											</DeleteDomainRequest>
										'.$this->__rf();
							
			if($this->__execute($SOAPMessage)) {
				return(true);
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}
	
	function GetDomainQuotaUsage($Domain) {
		// Build request
		$SOAPMessage = $this->__rh().'
										<GetQuotaUsageRequest xmlns="urn:zimbraAdmin" domain="' . $Domain . '">
										</GetQuotaUsageRequest>
									'.$this->__rf();
						
		if($this->__execute($SOAPMessage)) {
			return(true);
		} else {
			return(false);
		}
	}

}
?>
